<template>
  <AdVxeModal
    v-bind="$attrs"
    @register="register"
    :id="formIndex"
    :title="`${t('iot.route.device.variable.title')} - ${FormModeEntityRef.Display}`"
    :help-message="`${t('common.form')}：${formIndex}`"
    :cancelText="t('common.cancelText')"
    :close-func="handleClose"
    :okText="FormModeEntityRef.OkBtnTitle"
    @ok="handleOk"
    @open-change="handleOpenChange"
    width="50%"
  >
    <BasicForm @register="registerForm" @contextmenu="handleContextMenu">
      <template #expression="{ model, field }">
        <CodeEditor v-model:value="model[field]" :mode="MODE.CLIKE" :lineNumbers="true" />
      </template>
      <template #svExpression="{ model, field }">
        <CodeEditor v-model:value="model[field]" :mode="MODE.CLIKE" :lineNumbers="true" />
      </template>
    </BasicForm>
  </AdVxeModal>

  <PrintTemplateModal @register="templateModalRegister" v-bind="templateModalProps" />
</template>

<script lang="ts" setup>
  import type { PropType } from 'vue';
  import { ref } from 'vue';

  import { AdVxeModal, useModalInner } from '@/components/AdVxeModal';
  import { BasicForm, useForm, FormSchema } from '@/components/Form';
  import { PrintTemplateModal, useAdPrint } from '@/components/AdPrint';
  import { CodeEditor, MODE } from '@/components/CodeMirrorEditor';

  import { useI18n } from '@/hooks/web/useI18n';
  import { useContextMenu } from '@/hooks/web/useContextMenu';
  import { destroyContextMenu } from '@/components/ContextMenu';
  import { isFunction } from '@/utils/is';

  import { FormModeEnum, FormModeEntity } from '@/enums/formEnum';
  import { ValueTypeEnum, getValueTypeEnumSchema } from '@/enums/iot/valueTypeEnum';
  import { EndianFormatEnum, getEndianFormatEnumSchema } from '@/enums/iot/endianFormatEnum';
  import {
    ReadWritePermissionEnum,
    getReadWritePermissionEnumSchema,
  } from '@/enums/iot/readWritePermissionEnum';

  import { AjaxResult } from '#/request';
  import { DeviceVariableInputDto, DeviceVariableOutputDto } from '@/api/iot/admin/device/model';
  import {
    readDeviceNodes,
    getDeviceVariableReadMethod,
    getDeviceVariableWriteMethod,
    createDeviceVariable,
    updateDeviceVariable,
    deleteDeviceVariable,
  } from '@/api/iot/admin/device';

  defineOptions({ name: 'DeviceVariableModal' });
  const props = defineProps({
    /** 关闭回调，返回true关闭窗体 */
    closeFunc: {
      type: Function as PropType<
        (formMode: FormModeEnum, record?: DeviceVariableOutputDto) => Promise<boolean>
      >,
      default: null,
    },
    /** 提交前回调，返回false不执行内置提交逻辑，返回true执行内置提交逻辑 */
    beforeSubmitFunc: {
      type: Function as PropType<
        (formMode: FormModeEnum, record?: DeviceVariableOutputDto) => Promise<boolean>
      >,
      default: null,
    },
    /** 提交后回调，返回true关闭窗体 */
    afterSubmitFunc: {
      type: Function as PropType<
        (
          formMode: FormModeEnum,
          result?: AjaxResult | null,
          record?: DeviceVariableOutputDto,
        ) => Promise<boolean>
      >,
      default: null,
    },
  });

  const { t } = useI18n();
  const [createContextMenu] = useContextMenu();
  const formIndex = 'iot_devicevariable_detail';
  const keyField = 'Id';

  const formModeRef = ref<FormModeEnum>(FormModeEnum.Ok);
  const FormModeEntityRef = ref<FormModeEntity>(new FormModeEntity(formModeRef.value));

  const valueTypeEnumSchema = getValueTypeEnumSchema();
  const endianFormatEnumSchema = getEndianFormatEnumSchema();
  const readWritePermissionEnumSchema = getReadWritePermissionEnumSchema();

  const schemas: FormSchema[] = [
    {
      field: 'Id',
      helpMessage: `${t('common.field')}：${'Id'}`,
      component: 'Input',
      label: t('entity.idTitle'),
      componentProps: { disabled: true },
      colProps: {
        // span: 12,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 12, // ≥1200px
        xxl: 12, // ≥1600px
        // xxxl: 12, // ≥2000px 3.0
      },
    },
    {
      field: 'DeviceId',
      helpMessage: `${t('common.field')}：${'DeviceId'}`,
      component: 'ApiSelect',
      label: t('iot.route.device.title'),
      required: true,
      componentProps: {
        api: readDeviceNodes,
        // use name as label
        labelField: 'Name',
        // use id as value
        valueField: 'Id',
        showSearch: true,
        optionFilterProp: 'Name',
        // not request untill to select
        immediate: true,
      },
      colProps: {
        // span: 12,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 12, // ≥1200px
        xxl: 12, // ≥1600px
        // xxxl: 12, // ≥2000px 3.0
      },
    },
    // {
    //   field: 'DeviceName',
    //   helpMessage: `${t('common.field')}：${'DeviceName'}`,
    //   component: 'Input',
    //   label: t('iot.route.device.nameText'),
    //   ifShow: false,
    // },
    {
      field: 'Name',
      helpMessage: `${t('common.field')}：${'Name'}`,
      component: 'Input',
      label: t('iot.route.device.variable.nameText'),
      required: true,
      colProps: {
        // span: 12,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 12, // ≥1200px
        xxl: 12, // ≥1600px
        // xxxl: 12, // ≥2000px 3.0
      },
    },
    {
      field: 'Description',
      helpMessage: `${t('common.field')}：${'Description'}`,
      component: 'Input',
      label: t('iot.route.device.variable.descriptionText'),
      colProps: {
        // span: 12,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 12, // ≥1200px
        xxl: 12, // ≥1600px
        // xxxl: 12, // ≥2000px 3.0
      },
    },
    {
      field: 'Upload',
      helpMessage: `${t('common.field')}：${'Upload'}`,
      component: 'Switch',
      label: t('iot.route.device.variable.uploadText'),
      defaultValue: true,
      colProps: {
        // span: 12,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 12, // ≥1200px
        xxl: 12, // ≥1600px
        // xxxl: 12, // ≥2000px 3.0
      },
    },
    {
      field: 'PermissionType',
      helpMessage: `${t('common.field')}：${'PermissionType'}`,
      component: 'Select',
      label: t('iot.route.device.variable.permissionTypeText'),
      defaultValue: ReadWritePermissionEnum.ReadOnly,
      componentProps: {
        options: readWritePermissionEnumSchema,
        showSearch: true,
        optionFilterProp: 'label',
      },
      colProps: {
        // span: 12,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 12, // ≥1200px
        xxl: 12, // ≥1600px
        // xxxl: 12, // ≥2000px 3.0
      },
    },
    {
      field: 'ReadMethod',
      helpMessage: `${t('common.field')}：${'ReadMethod'}`,
      component: 'ApiSelect',
      label: t('iot.route.device.variable.readMethodText'),
      defaultValue: '',
      // slot: 'readMethod',
      componentProps: ({ formModel }) => {
        return {
          api: getDeviceVariableReadMethod,
          params: formModel.DeviceId,
          // use name as label
          labelField: 'Name',
          // use id as value
          valueField: 'Method',
          showSearch: true,
          optionFilterProp: 'Name',
          // not request untill to select
          immediate: false,
        };
      },
      colProps: {
        // span: 12,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 12, // ≥1200px
        xxl: 12, // ≥1600px
        // xxxl: 12, // ≥2000px 3.0
      },
    },
    {
      field: 'ReadAddress',
      helpMessage: `${t('common.field')}：${'ReadAddress'}`,
      component: 'Input',
      label: t('iot.route.device.variable.readAddressText'),
      colProps: {
        // span: 12,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 12, // ≥1200px
        xxl: 12, // ≥1600px
        // xxxl: 12, // ≥2000px 3.0
      },
    },
    {
      field: 'WriteMethod',
      helpMessage: `${t('common.field')}：${'WriteMethod'}`,
      component: 'ApiSelect',
      label: t('iot.route.device.variable.writeMethodText'),
      defaultValue: '',
      // slot: 'writeMethod',
      componentProps: ({ formModel }) => {
        return {
          api: getDeviceVariableWriteMethod,
          params: formModel.DeviceId,
          // use name as label
          labelField: 'Name',
          // use id as value
          valueField: 'Method',
          showSearch: true,
          optionFilterProp: 'Name',
          // not request untill to select
          immediate: false,
        };
      },
      colProps: {
        // span: 12,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 12, // ≥1200px
        xxl: 12, // ≥1600px
        // xxxl: 12, // ≥2000px 3.0
      },
    },
    {
      field: 'WriteAddress',
      helpMessage: `${t('common.field')}：${'WriteAddress'}`,
      component: 'Input',
      label: t('iot.route.device.variable.writeAddressText'),
      colProps: {
        // span: 12,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 12, // ≥1200px
        xxl: 12, // ≥1600px
        // xxxl: 12, // ≥2000px 3.0
      },
    },
    {
      field: 'ValueType',
      helpMessage: `${t('common.field')}：${'ValueType'}`,
      component: 'Select',
      label: t('iot.route.device.variable.valueTypeText'),
      defaultValue: ValueTypeEnum.Any,
      componentProps: {
        options: valueTypeEnumSchema,
        showSearch: true,
        optionFilterProp: 'label',
      },
      colProps: {
        // span: 12,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 12, // ≥1200px
        xxl: 12, // ≥1600px
        // xxxl: 12, // ≥2000px 3.0
      },
    },
    {
      field: 'Endian',
      helpMessage: `${t('common.field')}：${'Endian'}`,
      component: 'Select',
      label: t('iot.route.device.variable.endianText'),
      defaultValue: EndianFormatEnum.None,
      componentProps: {
        options: endianFormatEnumSchema,
        showSearch: true,
        optionFilterProp: 'label',
      },
      colProps: {
        // span: 12,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 12, // ≥1200px
        xxl: 12, // ≥1600px
        // xxxl: 12, // ≥2000px 3.0
      },
    },
    {
      field: 'ValueNormal',
      helpMessage: `${t('common.field')}：${'ValueNormal'}`,
      component: 'Input',
      label: t('iot.route.device.variable.valueNormalText'),
      colProps: {
        // span: 24,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 24, // ≥1200px
        xxl: 24, // ≥1600px
        // xxxl: 24, // ≥2000px 3.0
      },
    },
    {
      field: 'Expression',
      helpMessage: `${t('common.field')}：${'Expression'}`,
      // component: 'Input',
      label: t('iot.route.device.variable.expressionText'),
      slot: 'expression',
      colProps: {
        // span: 24,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 24, // ≥1200px
        xxl: 24, // ≥1600px
        // xxxl: 24, // ≥2000px 3.0
      },
    },
    {
      field: 'SvWhnChg',
      helpMessage: `${t('common.field')}：${'SvWhnChg'}`,
      component: 'Switch',
      label: t('iot.route.device.variable.svWhnChgText'),
      defaultValue: false,
      colProps: {
        // span: 12,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 12, // ≥1200px
        xxl: 12, // ≥1600px
        // xxxl: 12, // ≥2000px 3.0
      },
    },
    {
      field: 'OrderNumber',
      helpMessage: `${t('common.field')}：${'OrderNumber'}`,
      component: 'InputNumber',
      label: t('iot.route.device.variable.orderNumberText'),
      componentProps: {
        style: { width: '100%' },
      },
      colProps: {
        // span: 12,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 12, // ≥1200px
        xxl: 12, // ≥1600px
        // xxxl: 12, // ≥2000px 3.0
      },
    },
    {
      field: 'SvExpression',
      helpMessage: `${t('common.field')}：${'SvExpression'}`,
      // component: 'InputTextArea',
      label: t('iot.route.device.variable.svExpressionText'),
      slot: 'svExpression',
      colProps: {
        // span: 24,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 24, // ≥1200px
        xxl: 24, // ≥1600px
        // xxxl: 24, // ≥2000px 3.0
      },
    },
    {
      field: 'Remark',
      helpMessage: `${t('common.field')}：${'Remark'}`,
      component: 'InputTextArea',
      label: t('iot.route.device.variable.remarkText'),
      componentProps: {
        showCount: false,
      },
      colProps: {
        // span: 24,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 24, // ≥1200px
        xxl: 24, // ≥1600px
        // xxxl: 24, // ≥2000px 3.0
      },
    },
    { field: 'divider-basic', component: 'Divider', label: '', colProps: { span: 24 } },
    {
      field: 'CreatedTime',
      helpMessage: `${t('common.field')}：${'CreatedTime'}`,
      component: 'DatePicker',
      label: t('entity.creationAudited.createdTimeTitle'),
      componentProps: {
        disabled: true,
        showTime: true,
        valueFormat: 'YYYY-MM-DD HH:mm:ss',
        style: { width: '100%' },
      },
      colProps: {
        // span: 12,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 12, // ≥1200px
        xxl: 12, // ≥1600px
        // xxxl: 12, // ≥2000px 3.0
      },
    },
    {
      field: 'UpdatedTime',
      helpMessage: `${t('common.field')}：${'UpdatedTime'}`,
      component: 'DatePicker',
      label: t('entity.updateAudited.updatedTimeTitle'),
      componentProps: {
        disabled: true,
        showTime: true,
        valueFormat: 'YYYY-MM-DD HH:mm:ss',
        style: { width: '100%' },
      },
      colProps: {
        // span: 12,
        xs: 24, // <576px
        sm: 24, // ≥576px
        md: 24, // ≥768px
        lg: 24, // ≥992px
        xl: 12, // ≥1200px
        xxl: 12, // ≥1600px
        // xxxl: 12, // ≥2000px 3.0
      },
    },
  ];

  const [registerForm, { resetFields, getFieldsValue, setFieldsValue, validate }] = useForm({
    labelWidth: 150,
    schemas: schemas,
    showActionButtonGroup: false,
    compact: true,
  });

  const [register, { setModalProps, closeModal, changeLoading }] = useModalInner(async (data) => {
    changeLoading(true);
    try {
      await clearInputDto();
      let record = (data?.record || {}) as DeviceVariableOutputDto;
      if (data.formMode) {
        formModeRef.value = data.formMode as FormModeEnum;
        FormModeEntityRef.value = new FormModeEntity(formModeRef.value);
      }
      if (record) {
        await setInputDto({
          ...record,
        });
      }
    } finally {
      changeLoading(false);
    }
  });

  //#region "加载状态"
  const loadingRef = ref(false);
  /** 开启加载状态 */
  function openLoading() {
    changeLoading(true);
    setModalProps({ okLoading: true, cancelLoading: true });
    loadingRef.value = true;
  }
  /** 关闭加载状态 */
  function closeLoading() {
    changeLoading(false);
    setModalProps({ okLoading: false, cancelLoading: false });
    loadingRef.value = false;
  }
  //#endregion
  //#region 定义高级打印
  const { printContextMenus, templateModalRegister, templateModalProps } = useAdPrint({
    formIndex: formIndex,
    keyField: keyField,
    getFormData: () => getFieldsValue(),
  });
  /** 处理上下文菜单(右键菜单) */
  function handleContextMenu(e: MouseEvent) {
    const element = document.elementFromPoint(e.clientX, e.clientY) as Element;
    const cursor = document.defaultView?.getComputedStyle(element, null).cursor;
    // console.log('handleContextMenu', {
    //   cursor: cursor,
    // });

    let items: any[] = [];
    switch (FormModeEntityRef.value.FormMode) {
      case FormModeEnum.Ok:
      case FormModeEnum.Edit:
      case FormModeEnum.ReadOnly:
        if (!cursor || cursor === 'default' || cursor === 'auto') {
          items = [...printContextMenus];
        }
        break;
    }
    if (items && items?.length > 0) {
      createContextMenu({
        event: e,
        styles: {
          border: '1px solid #eee',
          'border-radius': '2px',
          'box-shadow': '3px 3px 3px rgb(0 0 0 / 15%)',
        },
        items: [...items],
      });
    }
  }
  //#endregion

  /** 获取输入DTO */
  function getInputDto(): DeviceVariableInputDto {
    const record = getFieldsValue() as DeviceVariableInputDto;
    return record;
  }
  /** 设置输入DTO */
  async function setInputDto(values: any) {
    let inputDto = getInputDto();
    inputDto = { ...inputDto, ...values };
    await setFieldsValue({ ...inputDto });
  }
  /** 清除输入DTO */
  async function clearInputDto() {
    await resetFields();
  }

  /** 获取输出DTO */
  function getOutputDto(): DeviceVariableOutputDto {
    const record = getFieldsValue() as DeviceVariableOutputDto;
    return record;
  }

  /** 处理关闭按钮 */
  async function handleClose() {
    openLoading();

    const { closeFunc } = props;
    try {
      if (closeFunc && isFunction(closeFunc)) {
        const outputDto = getOutputDto();
        const result = await closeFunc(FormModeEntityRef.value.FormMode, outputDto);
        return result;
      }
    } finally {
      closeLoading();
    }
    return true;
  }
  /** 处理确定按钮 */
  async function handleOk() {
    const data = await validate();
    if (!data) return;
    //console.log(data);

    openLoading();
    const { beforeSubmitFunc, afterSubmitFunc } = props;
    try {
      const inputDto = getInputDto();
      const outputDto = getOutputDto();
      // console.log('handleOk', inputDto);
      let innerSubmit = true;
      let innerCloseModal = true;
      if (beforeSubmitFunc && isFunction(beforeSubmitFunc)) {
        innerSubmit = await beforeSubmitFunc(FormModeEntityRef.value.FormMode, outputDto);
      }
      let result: AjaxResult | null = null;
      if (innerSubmit) {
        switch (FormModeEntityRef.value.FormMode) {
          case FormModeEnum.Add:
            result = await createDeviceVariable([inputDto]);
            break;
          case FormModeEnum.Edit:
            result = await updateDeviceVariable([inputDto]);
            break;
          case FormModeEnum.Delete:
            result = await deleteDeviceVariable([inputDto.Id]);
            break;
        }
      }
      if (afterSubmitFunc && isFunction(afterSubmitFunc)) {
        innerCloseModal = await afterSubmitFunc(
          FormModeEntityRef.value.FormMode,
          result,
          outputDto,
        );
      }
      if (innerCloseModal) {
        closeModal();
      }
    } finally {
      closeLoading();
    }
  }

  /** 打开或者关闭触发 */
  function handleOpenChange(open: boolean) {
    if (!open) {
      destroyContextMenu();
    }
  }
</script>
<style lang="less" scoped></style>
